<?php
class ScoreCalculator {

    private $redisManager;
    private $logger;
    private $config;
    public function __construct() {
        $this->redisManager = new RedisManager();
        $date = date('YmdHis');
        $this->logger = new Logger('logs/log'.$date.'.log');
        $this->config = new Config();
    }

    /**
     * 计算手牌分数
     * @param $gameId
     * @param $cards
     * @return array
     */
    public function calculateScore($gameId, $cards): array
    {
        // 检测牌型
        $handType = $this->detectHandType($cards);
        // 计算基础分数
        $baseScore = $this->calculateBaseScore($cards, $handType);
        // 倍率
        $rate = $this->config->get('hand_type')[$handType];

        if ($this->redisManager->getGameData($gameId, 'critical_strike'))
        {
            // 翻倍道具
            $rate *= 2;
        }

        if ($this->redisManager->getGameData($gameId, 'hand_type_multiplier') == $handType) {
            $rate *= 2;
        }

        $totalScore = $baseScore * $rate;

        return [
            'hand_type' => $handType,
            'base_score' => $baseScore,
            'multiplier' => $rate,
            'total_score' => $totalScore,
            'cards' => $cards
        ];
    }

    /**
     * 检测手牌类型
     * @param array $cards 手牌数组
     * @return string 牌型标识
     */
    private function detectHandType(array $cards): string
    {
        // 单牌直接返回高牌
        if (count($cards) === 1) {
            return '高牌';
        }
        $this->logger->info("检测牌型，出牌: " . json_encode($cards, JSON_UNESCAPED_UNICODE));

        // 提取牌值和花色
        $values = array_column($cards, 'value');
        $this->logger->info("牌值: " . json_encode($values, JSON_UNESCAPED_UNICODE));

        $suits = array_column($cards, 'suit');
        $this->logger->info("花色: " . json_encode($suits, JSON_UNESCAPED_UNICODE));

        // 统计牌值和花色的出现次数
        $valueCounts = array_count_values($values);
        $this->logger->info("牌值计数: " . json_encode($valueCounts, JSON_UNESCAPED_UNICODE));

        $suitCounts = array_count_values($suits);
        $this->logger->info("花色计数: " . json_encode($suitCounts, JSON_UNESCAPED_UNICODE));

        // 检查是否为同花（所有牌花色相同）
        $isFlush = count($suitCounts) === 1 && count($cards) >= 3;

        // 检查是否为顺子
        $isStraight = $this->isStraight($values);
        $this->logger->info("是否为顺子: " . print_r($isStraight, true));

        // 检查是否为同花顺（同花且顺子）
        if ($isFlush && $isStraight) {
            return '同花顺';
        }

        // 检查四条（四张相同牌值）
        if ($this->hasNOfAKind($valueCounts, 4) && count($cards) === 4) {
            return '四条';
        }

        // 检查葫芦（三条加一对）
        if ($this->isFullHouse($valueCounts)) {
            return '葫芦';
        }

        // 检查同花
        if ($isFlush) {
            return '同花';
        }

        // 检查顺子
        if ($isStraight) {
            return '顺子';
        }

        // 检查三条
        if ($this->hasNOfAKind($valueCounts, 3) && count($cards) === 3) {
            return '三条';
        }

        // 检查两对
        if ($this->countPairs($valueCounts) === 2 && count($cards) === 4) {
            return '两对';
        }

        // 检查一对
        if ($this->countPairs($valueCounts) === 1 && count($cards) === 2) {
            return '对子';
        }

        // 默认返回高牌
        return '高牌';
    }


    /**
     * 检查是否为葫芦（三条+一对）
     * @param array $valueCounts 牌值计数数组
     * @return bool
     */
    private function isFullHouse(array $valueCounts): bool {
        $hasThree = false;
        $hasTwo = false;

        foreach ($valueCounts as $count) {
            if ($count === 3) {
                $hasThree = true;
            } elseif ($count === 2) {
                $hasTwo = true;
            }
        }
        return $hasThree && $hasTwo;
    }


    /**
     * 检查是否有N张相同的牌（例如四条或三条）
     * @param array $valueCounts 牌值计数数组
     * @param int $n 需要匹配的数量
     * @return bool
     */
    private function hasNOfAKind(array $valueCounts, int $n): bool
    {
        return in_array($n, $valueCounts);
    }

    /**
     * 统计对子的数量
     * @param array $valueCounts 牌值计数数组
     * @return int
     */
    private function countPairs(array $valueCounts): int
    {
        $pairs = 0;
        foreach ($valueCounts as $count) {
            if ($count === 2) $pairs++;
        }
        return $pairs;
    }

    /**
     * 检查是否为顺子
     * @param array $values 牌值数组（已排序）
     * @return bool
     */
    private function isStraight(array $values): bool {
        // 单牌或少于3张牌不可能是顺子
        if (count($values) < 3) {
            return false;
        }

        // 排序牌值（从小到大）
        sort($values);

        $this->logger->info("检查顺子，牌值: " . json_encode($values));


        // 处理A-2-3-4-5的特殊顺子
        if (in_array(14, $values) && in_array(2, $values) && in_array(3, $values) &&
            in_array(4, $values) && in_array(5, $values)) {
            return true;
        }

        // 检查普通顺子（连续递增）
        for ($i = 0; $i < count($values) - 1; $i++) {
            if ($values[$i] + 1 !== $values[$i + 1]) {
                return false;
            }
        }

        return true;
    }


    /**
     * 计算基础分数
     * @param array $cards 手牌数组
     * @param string $handType 牌型标识
     * @return float|int 基础分数
     */
    private function calculateBaseScore(array $cards, string $handType): float|int
    {
        $values = array_column($cards, 'value');

        return array_sum($values);
    }

}
?>